home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 30 / Amiga Format AFCD30 (Sep 1998, Issue 114).iso / -seriously_amiga- / workbench / -datatypes- / mpegsystem / dispatch.c < prev    next >
C/C++ Source or Header  |  1998-06-18  |  79KB  |  2,375 lines

  1.  
  2. /*
  3. **
  4. **  $VER: dispatch.c 1.5 (1.6.98)
  5. **  mpegsystem.datatype 1.5
  6. **
  7. **  Dispatch routine for a DataTypes class
  8. **
  9. **  Written 1997/1998 by Roland 'Gizzy' Mainz
  10. **  Original example source from David N. Junod
  11. **
  12. */
  13.  
  14. /* main includes */
  15. #include "classbase.h"
  16. #include "classdata.h"
  17.  
  18. /*****************************************************************************/
  19.  
  20. /* is animation.datatype V41 ? */
  21. #define ISV41 ((cb -> cb_SuperClassBase -> lib_Version) == 41U)
  22.  
  23. /*****************************************************************************/
  24.  
  25.  
  26. /* local prototypes */
  27.  
  28. /* virtual demux fs-handler related */
  29. DISPATCHERFLAGS static void              Handler( void );
  30.                 static void              RunHandler( struct ClassBase *cb, struct MPEGSystemInstData *msid );
  31.                 static void              KillHandler( struct ClassBase *cb, struct MPEGSystemInstData *msid );
  32.                 static void              dispatch_packet( struct ClassBase *cb, struct MPEGSystemInstData *msid, struct DosPacket *dp );
  33.                 static BPTR              GetStreamLock( struct ClassBase *cb, struct MPEGSystemInstData *msid, ULONG num, BOOL isaudio );
  34.                 static void              FreeLock( struct ClassBase *cb, struct MPEGSystemInstData *msid, struct FileLock *fl );
  35.  
  36.                 static BOOL              SendSeek( struct ClassBase *, struct MPEGSystemInstData *, struct FileHandle *, LONG, LONG );
  37.                 static BOOL              SendRead( struct ClassBase *, struct MPEGSystemInstData *, struct FileHandle *, UBYTE *, ULONG );
  38.                 static struct DosPacket *ObtainDOSPacket( struct ClassBase *, struct MPEGSystemInstData * );
  39.                 static void              ReleaseDOSPacket( struct ClassBase *, struct MPEGSystemInstData *, struct DosPacket * );
  40.  
  41.                 static void              STRPTR2BSTR( STRPTR s );
  42.  
  43. /* MPEG system stream demultiplexer related */
  44.                 static UBYTE            *get_buf_data( struct ClassBase *cb, struct MPEGSystemInstData *msid, long read_len );
  45.                 static UBYTE            *calc_time_stamp( struct ClassBase *cb, struct MPEGSystemInstData *msid, UBYTE *buf_ptr , long *time_stamp );
  46.                 static UBYTE             get_next_start_code( struct ClassBase *cb, struct MPEGSystemInstData *msid );
  47.                 static void              read_pack_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACK_header *pki );
  48.                 static void              read_system_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, SYSTEM_header *si );
  49.                 static void              read_packet_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACKET_header *pi );
  50.                 static void              print_pack_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACK_header *pki );
  51.                 static void              print_system_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, SYSTEM_header *si );
  52.                 static void              print_packet_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACKET_header *pi );
  53.  
  54.                 static void              exitdemux( struct ClassBase *cb, struct MPEGSystemInstData *msid, LONG result, LONG result2 );
  55.                 static void              demux( struct ClassBase *cb, struct MPEGSystemInstData *msid, BPTR file );
  56.  
  57. /* class related */
  58.                 static BOOL              ScanFrames( struct ClassBase *, Object * );
  59.                 static void              mysprintf( struct ClassBase *, STRPTR, STRPTR, ... );
  60.  
  61.                 static ULONG             SaveMPEGSystem( struct ClassBase *cb, struct IClass *cl, Object *o, struct dtWrite *dtw );
  62.  
  63. /*****************************************************************************/
  64.  
  65. /* Create "mpegsystem.datatype" BOOPSI class */
  66. struct IClass *initClass( struct ClassBase *cb )
  67. {
  68.     struct IClass *cl;
  69.  
  70.     /* Create our class... */
  71.     if( cl = MakeClass( MPEGSYSTEMDTCLASS, ANIMATIONDTCLASS, NULL, (ULONG)sizeof( struct MPEGSystemInstData ), 0UL ) )
  72.     {
  73. #define DTSTACKSIZE (16384UL)
  74.       cl -> cl_Dispatcher . h_Entry    = (HOOKFUNC)StackSwapDispatch; /* see stackswap.c */
  75.       cl -> cl_Dispatcher . h_SubEntry = (HOOKFUNC)Dispatch;          /* see stackswap.c */
  76.       cl -> cl_Dispatcher . h_Data     = (APTR)DTSTACKSIZE;           /* see stackswap.c */
  77.       cl -> cl_UserData                = (ULONG)cb;
  78.  
  79.       AddClass( cl );
  80.     }
  81.  
  82.     return( cl );
  83. }
  84.  
  85. /*****************************************************************************/
  86.  
  87. /* class dispatcher */
  88. DISPATCHERFLAGS
  89. ULONG Dispatch( REGA0 struct IClass *cl, REGA2 Object *o, REGA1 Msg msg )
  90. {
  91.     struct ClassBase           *cb = (struct ClassBase *)(cl -> cl_UserData);
  92.     struct MPEGSystemInstData  *msid;
  93.     ULONG                       retval = 0UL;
  94.  
  95.     switch( msg -> MethodID )
  96.     {
  97. /****** mpegsystem.datatype/OM_NEW *******************************************
  98. *
  99. *    NAME
  100. *        OM_NEW -- Create a mpegsystem.datatype object.
  101. *
  102. *    FUNCTION
  103. *        The OM_NEW method is used to create an instance of the
  104. *        mpegsystem.datatype class.  This method is passed to the superclass
  105. *        first. After this, mpegsystem.datatype parses the prefs file and 
  106. *        makes a scan through the system stream to get index information 
  107. *        about the single system stream packets.
  108. *        After all, the mpegsystem.datatype starts two objects which reads
  109. *        the single video and audio streams trougth an internal
  110. *        "demultiplexer" (system stream splitter) filesystem.
  111. *
  112. *        Subclasses of mpegsystem.datatype are not supported. Any attempt to
  113. *        create a subclass object of mpegsystem.datatype will be rejected by
  114. *        this method.
  115. *
  116. *    ATTRIBUTES
  117. *        The following attributes can be specified at creation time.
  118. *
  119. *        DTA_SourceType (ULONG) -- Determinates the type of DTA_Handle
  120. *            attribute. Only DTST_FILE is supported.
  121. *            If any other type was set in a given DTA_SourceType,
  122. *            OM_NEW will be rejected.
  123. *            Defaults to DTST_FILE.
  124. *
  125. *        DTA_Handle -- For DTST_FILE, a BPTR filehandle is expected. This
  126. *            handle will be created by datatypesclass depeding on the DTF_#?
  127. *            flag, which is DTF_BINARY here.  DTST_FILE, datatypesclass
  128. *            creates a file handle from the given DTA_Name and DTA_Handle
  129. *            (a BPTR returned by Lock).
  130. *            A DTST_RAM (create empty object) source type requires a NULL
  131. *            handle.
  132. *
  133. *    RESULT
  134. *        If the object was created a pointer to the object is returned,
  135. *        otherwise NULL is returned.
  136. *
  137. ******************************************************************************
  138. *
  139. */
  140.       case OM_NEW:
  141.       {
  142.           struct TagItem *ti;
  143.  
  144.           /* We only support DTST_FILE or DTST_RAM as source type */
  145.           if( ti = FindTagItem( DTA_SourceType, (((struct opSet *)msg) -> ops_AttrList) ) )
  146.           {
  147.             if( ((ti -> ti_Data) != DTST_FILE)
  148. #ifdef HAS_ENCODER
  149. && ((ti -> ti_Data) != DTST_RAM)
  150. #endif /* HAS_ENCODER */
  151.  )
  152.             {
  153.               SetIoErr( ERROR_OBJECT_WRONG_TYPE );
  154.  
  155.               break;
  156.             }
  157.           }
  158.  
  159. #ifndef HAS_ENCODER
  160.           /* This must not be a subclass of mpegsystem.datatype
  161.            * (not implemented yet)
  162.            */
  163.           if( o == (Object *)cl )
  164. #endif /* !HAS_ENCODER */
  165.           {
  166.             if( retval = DoSuperMethodA( cl, o, msg ) )
  167.             {
  168.               /* Load/scan frames... */
  169.               if( !ScanFrames( cb, (Object *)retval ) )
  170.               {
  171.                 /* Something went fatally wrong, dispose object */
  172.                 CoerceMethod( cl, (Object *)retval, OM_DISPOSE );
  173.                 retval = 0UL;
  174.               }
  175.             }
  176.           }
  177. #ifndef HAS_ENCODER
  178.           else
  179.           {
  180.             /* Subclasses of mpegsystem.datatype are not implemented */
  181.             SetIoErr( ERROR_NOT_IMPLEMENTED );
  182.           }
  183. #endif /* !HAS_ENCODER */
  184.       }
  185.           break;
  186.  
  187. /****** mpegsystem.datatype/OM_DISPOSE ***************************************
  188. *
  189. *    NAME
  190. *        OM_DISPOSE -- Delete a mpegsystem.datatype object.
  191. *
  192. *    FUNCTION
  193. *        The OM_DISPOSE method is used to delete an instance of the
  194. *        mpegsystem.datatype class. This method is passed to the superclass
  195. *        when it has completed.
  196. *
  197. *    RESULT
  198. *        The object is deleted. 0UL is returned.
  199. *
  200. ******************************************************************************
  201. *
  202. */
  203.       case OM_DISPOSE:
  204.       {
  205.           LONG saved_ioerr = IoErr(); /* Preserve I/O error */
  206.  
  207.           /* Get a pointer to our object data */
  208.           msid = (struct MPEGSystemInstData *)INST_DATA( cl, o );
  209.  
  210.           /* Wait for any outstanding blitter usage (which may use one of our bitmaps) */
  211.           WaitBlit();
  212.  
  213.           /* Dispose the current audio and video objects */
  214.           DisposeDTObject( (msid -> msid_CurrVideo) );
  215.           DisposeDTObject( (msid -> msid_CurrAudio) );
  216.  
  217.           /* Kill our virtual demux handler */
  218.           KillHandler( cb, msid );
  219.  
  220.           /* Delete the frame pool */
  221.           DeletePool( (msid -> msid_Pool) );
  222.  
  223.           /* Close verbose output file */
  224.           if( (msid -> msid_VerboseOutput) && ((msid -> msid_VerboseOutput) != -1L) )
  225.           {
  226.             Close( (msid -> msid_VerboseOutput) );
  227.           }
  228.  
  229.           /* Dispose object */
  230.           DoSuperMethodA( cl, o, msg );
  231.  
  232.           /* Restore I/O error */
  233.           SetIoErr( saved_ioerr );
  234.       }
  235.           break;
  236.  
  237.       case OM_UPDATE:
  238.       {
  239.           if( DoMethod( o, ICM_CHECKLOOP ) )
  240.           {
  241.             break;
  242.           }
  243.       }
  244.       case OM_SET:
  245.       {
  246.           /* Pass the attributes to the animation class and force a refresh if we need it */
  247.           if( retval = DoSuperMethodA( cl, o, msg ) )
  248.           {
  249. /* The following statement is commented out because mpegsystem.datatype does not allow
  250.  * subclasses when the executable was compiled without the HAS_ENCODER define. Thus, the
  251.  * following statement is NOP unless subclasses are supported...
  252.  */
  253. #ifdef HAS_ENCODER
  254.             /* Top instance ? */
  255.             if( OCLASS( o ) == cl )
  256. #endif /* HAS_ENCODER */
  257.             {
  258.               struct RastPort *rp;
  259.  
  260.               /* Get a pointer to the rastport */
  261.               if( rp = ObtainGIRPort( (((struct opSet *)msg) -> ops_GInfo) ) )
  262.               {
  263.                 struct gpRender gpr;
  264.  
  265.                 /* Force a redraw */
  266.                 gpr . MethodID   = GM_RENDER;
  267.                 gpr . gpr_GInfo  = ((struct opSet *)msg) -> ops_GInfo;
  268.                 gpr . gpr_RPort  = rp;
  269.                 gpr . gpr_Redraw = GREDRAW_UPDATE;
  270.  
  271.                 DoMethodA( o, (Msg)(&gpr) );
  272.  
  273.                 /* Release the temporary rastport */
  274.                 ReleaseGIRPort( rp );
  275.  
  276.                 /* We did an update... */
  277.                 retval = 0UL;
  278.               }
  279.             }
  280.           }
  281.       }
  282.           break;
  283.  
  284. /****** mpegsystem.datatype/DTM_WRITE *******************************************
  285. *
  286. *    NAME
  287. *        DTM_WRITE -- Save data
  288. *
  289. *    FUNCTION
  290. *        This method saves the object's contents to disk.
  291. *
  292. *        If dtw_Mode is DTWM_IFF, the method is passed unchanged to the
  293. *        superclass, animation.datatype, which writes a single IFF ILBM
  294. *        picture.
  295. *
  296. *        If dtw_mode is DTWM_RAW, the object saved an MPEG System stream to
  297. *        the filehandle given, starting with the current frame until
  298. *        the end is reached.
  299. *        The sequence saved can be controlled by the ADTA_Frame, ADTA_Frames
  300. *        and ADTA_FrameIncrement attributes (see TAGS section below).
  301. *
  302. *    TAGS
  303. *        When writing the local ("raw") format, MPEG System movie, the
  304. *        following attributes are recognized:
  305. *
  306. *        ADTA_Frame (ULONG) - start frame, saving starts here.
  307. *            Defaults to the current frame displayed.
  308. *
  309. *        ADTA_Frames (ULONG) - the number of frames to be saved,
  310. *            Defaults to (max_num_of_frames - curr_frame).
  311. *
  312. *        ADTA_FrameIncrement (ULONG) - frame increment when saving.
  313. *            Defaults to 1, which means: "jump to next frame".
  314. *
  315. *    NOTE
  316. *        This function is not implemented yet. A possible implementation 
  317. *        would implement ACTION_WRITE in the virtial implementation and uses
  318. *        mpegvideo.datatype and mpegaudio.datatype encoders...
  319. *
  320. *    RESULT
  321. *        Returns 0 for failure (IoErr() returns result2), non-zero
  322. *        for success.
  323. *
  324. ******************************************************************************
  325. *
  326. */
  327.       case DTM_WRITE:
  328.       {
  329.           struct dtWrite *dtw;
  330.  
  331.           dtw = (struct dtWrite *)msg;
  332.  
  333.           /* Local data format (MPEG System) requested ? */
  334.           if( (dtw -> dtw_Mode) == DTWM_RAW )
  335.           {
  336.             retval = SaveMPEGSystem( cb, cl, o, dtw );
  337.           }
  338.           else
  339.           {
  340.             /* Pass msg to superclass (which writes a single frame as an IFF ILBM picture)... */
  341.             retval = DoSuperMethodA( cl, o, msg );
  342.           }
  343.       }
  344.           break;
  345.  
  346.  
  347. /****** mpegsystem.datatype/ADTM_LOADFRAME ***********************************
  348. *
  349. *    NAME
  350. *        ADTM_LOADFRAME -- Load frame
  351. *
  352. *    FUNCTION
  353. *        The ADTM_LOADFRAME method is used to obtain the bitmap and timing
  354. *        data of the animation.
  355. *        The method is passed to the embedded mpegvideo.datatype object.
  356. *        If successfull, the sample data of struct adtFrame are replaced
  357. *        by the corresponsing audio data from the embedded 
  358. *        mpegaudio.datatype object.
  359. *
  360. *    RESULT
  361. *        Returns the result from the embedded mpegvideo.datatype object
  362. *        (including Result2).
  363. *
  364. ******************************************************************************
  365. *
  366. */
  367.       case ADTM_LOADFRAME:
  368.       {
  369.           struct adtFrame *alf = (struct adtFrame *)msg;
  370.  
  371.           /* Get a pointer to our object data */
  372.           msid = (struct MPEGSystemInstData *)INST_DATA( cl, o );
  373.  
  374.           if( msid -> msid_CurrVideo )
  375.           {
  376.             if( retval = DoMethodA( (msid -> msid_CurrVideo), msg ) )
  377.             {
  378.               /* Add here the audio part..
  379.                * A better way would be to send SDTM_LOADSAMPLE to load the sample
  380.                * fragment
  381.                */
  382.               if( msid -> msid_Sample )
  383.               {
  384.                 UBYTE *sample        = msid -> msid_Sample;
  385.                 ULONG  sample_offset = (alf -> alf_Frame)            * (msid -> msid_SamplesPerFrame);
  386.                 ULONG  len           = ((alf -> alf_Duration) + 1UL) * (msid -> msid_SamplesPerFrame);
  387.  
  388.                 /* Sample completely out-of-range ? */
  389.                 if( sample_offset >= (msid -> msid_SampleLength) )
  390.                 {
  391.                   /* No sample data ! */
  392.                   sample        = NULL;
  393.                   sample_offset = 0UL;
  394.                   len           = 0UL;
  395.                 }
  396.                 else
  397.                 {
  398.                   /* Sample partial out of range ? */
  399.                   if( (sample_offset + len) > (msid -> msid_SampleLength) )
  400.                   {
  401.                     /* Cut it ! */
  402.                     len -= ((sample_offset + len) - (msid -> msid_SampleLength));
  403.                   }
  404.                 }
  405.  
  406.                 /* Fill in the message body */
  407.                 alf -> alf_Sample       = sample + sample_offset;
  408.                 alf -> alf_SampleLength = len;
  409.                 alf -> alf_Period       = msid -> msid_Period;
  410.               }
  411.             }
  412.           }
  413.           else
  414.           {
  415.             /* No mpegvideo.datatype object (Should not occur, but...). */
  416.             SetIoErr( ERROR_OBJECT_NOT_FOUND );
  417.           }
  418.       }
  419.           break;
  420.  
  421. /****** mpegsystem.datatype/ADTM_UNLOADFRAME ************************************
  422. *
  423. *    NAME
  424. *        ADTM_UNLOADFRAME -- Unload frame contents
  425. *
  426. *    FUNCTION
  427. *        The ADTM_UNLOADFRAME method is used to release the contents of a
  428. *        animation frame.
  429. *
  430. *        This method is passed to the embedded mpegvideo.datatype object.
  431. *
  432. *    RESULT
  433. *        Returns the result from the embedded mpegvideo.datatype object.
  434. *
  435. ******************************************************************************
  436. *
  437. */
  438.       case ADTM_UNLOADFRAME:
  439.       {
  440.           /* Get a pointer to our object data */
  441.           msid = (struct MPEGSystemInstData *)INST_DATA( cl, o );
  442.  
  443.           if( msid -> msid_CurrVideo )
  444.           {
  445.             retval = DoMethodA( (msid -> msid_CurrVideo), msg );
  446.  
  447.             /* Here we should do an SDTM_UNLOADSAMPLE if the sample data were
  448.              * obtained using SDTM_LOADSAMPLE
  449.              */
  450.           }
  451.       }
  452.           break;
  453.  
  454.       /* Let the superclass handle everything else */
  455.       default:
  456.       {
  457.           retval = DoSuperMethodA( cl, o, msg );
  458.       }
  459.           break;
  460.     }
  461.  
  462.     return( retval );
  463. }
  464.  
  465.  
  466. static
  467. BOOL ScanFrames( struct ClassBase *cb, Object *o )
  468. {
  469.     struct MPEGSystemInstData *msid     = (struct MPEGSystemInstData *)INST_DATA( (cb -> cb_Lib . cl_Class), o );
  470.     BOOL                       success  = FALSE;
  471.     LONG                       error    = 0L;
  472.  
  473.     InitSemaphore( (&(msid -> msid_SigSem)) );
  474.  
  475.     /* Create a memory pool for frame nodes */
  476.     if( msid -> msid_Pool = CreatePool( MEMF_PUBLIC, 8192UL, 8192UL ) )
  477.     {
  478.       BPTR  fh;               /* handle (file handle)      */
  479.       ULONG sourcetype;       /* type of stream (either DTST_FILE or DTST_RAM) */
  480.  
  481.       /* Prefs defaults */
  482.  
  483.       /* Read prefs */
  484.       ReadENVPrefs( cb, msid );
  485.  
  486.       /* Get file handle, handle type and BitMapHeader */
  487.       if( GetDTAttrs( o, DTA_SourceType,    (&sourcetype),
  488.                          DTA_Handle,        (&fh),
  489.                          DTA_Name,          (&(msid -> msid_ProjectName)),
  490.                          TAG_DONE ) == 3UL )
  491.       {
  492.         switch( sourcetype )
  493.         {
  494.           case DTST_FILE:
  495.           {
  496.               /* we have the filehandle - anything what we want... */
  497.           }
  498.               break;
  499.  
  500. #ifdef HAS_ENCODER
  501.           case DTST_RAM:
  502.           {
  503.               /* do nothing */
  504.           }
  505.               break;
  506. #endif /* HAS_ENCODER */
  507.  
  508.           default:
  509.           {
  510.               /* unsupported source type */
  511.               error = ERROR_NOT_IMPLEMENTED;
  512.           }
  513.               break;
  514.         }
  515.  
  516.         /* Any error ? */
  517.         if( error == 0L )
  518.         {
  519.           if( fh )
  520.           {
  521.             /* Run system-stream demultiplexer... */
  522.             demux( cb, msid, fh );
  523.  
  524.             /* ...success ? */
  525.             if( msid -> Handler . Process )
  526.             {
  527.               BPTR v_lock;
  528.  
  529.               /* Get first video stream */
  530.               if( v_lock = GetStreamLock( cb, msid, 0UL, FALSE ) )
  531.               {
  532.                 if( msid -> msid_CurrVideo = NewDTObject( NULL, DTA_SourceType, DTST_FILE,
  533.                                                                 DTA_Handle,     v_lock,
  534.                                                                 DTA_GroupID,    GID_ANIMATION,
  535.                                                                 TAG_DONE ) )
  536.                 {
  537.                   ULONG                 video_modeid;
  538.                   ULONG                *video_cregs;
  539.                   struct ColorRegister *video_cm;
  540.                   ULONG                 video_numcolors;
  541.                   ULONG                 video_animwidth,
  542.                                         video_animdepth,
  543.                                         video_animheight;
  544.                   ULONG                 video_frame,
  545.                                         video_numframes,
  546.                                         video_fps = 0UL,
  547.                                         video_tpf = 0UL;
  548.                   struct BitMap        *video_keyframe;
  549.  
  550.                   if( GetDTAttrs( (msid -> msid_CurrVideo),
  551.                                   ADTA_ModeID,                           (&video_modeid),
  552.                                   ADTA_CRegs,                            (&video_cregs),
  553.                                   ADTA_ColorRegisters,                   (&video_cm),
  554.                                   ADTA_NumColors,                        (&video_numcolors),
  555.                                   ADTA_Width,                            (&video_animwidth),
  556.                                   ADTA_Height,                           (&video_animheight),
  557.                                   ADTA_Depth,                            (&video_animdepth),
  558.                                   ADTA_Frame,                            (&video_frame),
  559.                                   ADTA_Frames,                           (&video_numframes),
  560.                                   XTAG( !ISV41, ADTA_FramesPerSecond ),  (&video_fps),
  561.                                   XTAG(  ISV41, ADTA_TicksPerFrame   ),  (&video_tpf),
  562.                                   ADTA_KeyFrame,                         (&video_keyframe),
  563.                                   TAG_DONE ) == 11UL )
  564.                   {
  565.                     /* This should NEVER fail, but... */
  566.                     if( video_numframes && video_keyframe && (video_fps || video_tpf) )
  567.                     {
  568.                       ULONG                *cregs;
  569.                       struct ColorRegister *cm;
  570.                       ULONG                 numcolors;
  571.  
  572.                       SetDTAttrs( o, NULL, NULL, ADTA_NumColors, video_numcolors, TAG_DONE );
  573.  
  574.                       if( GetDTAttrs( o, ADTA_CRegs,          (&cregs),
  575.                                          ADTA_ColorRegisters, (&cm),
  576.                                          ADTA_NumColors,      (&numcolors),
  577.                                          TAG_DONE ) == 3UL )
  578.                       {
  579.                         /* Check if we got memory for the palette (if we have one) */
  580.                         if( (cregs && cm && (numcolors == video_numcolors)) || (video_numcolors == 0UL) )
  581.                         {
  582.                           BPTR a_lock;
  583.  
  584.                           /* Copy base palette (if we have one) */
  585.                           if( video_numcolors )
  586.                           {
  587.                             CopyMem( video_cregs, cregs, (video_numcolors * 3UL * sizeof( ULONG )) );
  588.                             CopyMem( video_cm,    cm,    (video_numcolors * 3UL * sizeof( struct ColorRegister )) );
  589.                           }
  590.  
  591.                           msid -> msid_TicksPerFrame = ((ISV41)?(video_tpf):(TICK_FREQ / video_fps));
  592.  
  593.                           SetDTAttrs( o, NULL, NULL, DTA_ObjName,                           (msid -> msid_ProjectName),
  594.                                                      ADTA_ModeID,                           video_modeid,
  595.                                                      ADTA_Width,                            video_animwidth,
  596.                                                      ADTA_Height,                           video_animheight,
  597.                                                      ADTA_Depth,                            video_animdepth,
  598.                                                      ADTA_Frame,                            video_frame,
  599.                                                      ADTA_Frames,                           video_numframes,
  600.                                                      XTAG( !ISV41, ADTA_FramesPerSecond ),  video_fps,
  601.                                                      XTAG(  ISV41, ADTA_TicksPerFrame   ),  video_tpf,
  602.                                                      ADTA_KeyFrame,                         video_keyframe,
  603.                                                      TAG_DONE );
  604.  
  605.                           /* Get first audio stream */
  606.                           if( a_lock = GetStreamLock( cb, msid, 0UL, TRUE ) )
  607.                           {
  608.                             if( msid -> msid_CurrAudio = NewDTObject( NULL, DTA_SourceType, DTST_FILE,
  609.                                                                             DTA_Handle,     a_lock,
  610.                                                                             DTA_GroupID,    GID_SOUND,
  611.                                                                             TAG_DONE ) )
  612.                             {
  613.                               ULONG volume;
  614.  
  615.                               GetDTAttrs( (msid -> msid_CurrAudio), SDTA_Sample,       (&(msid -> msid_Sample)),
  616.                                                                     SDTA_SampleLength, (&(msid -> msid_SampleLength)),
  617.                                                                     SDTA_Period,       (&(msid -> msid_Period)),
  618.                                                                     SDTA_Volume,       (&volume),
  619.                                                                     TAG_DONE );
  620.  
  621.                               msid -> msid_SamplesPerFrame = ((SysBase -> ex_EClockFrequency) * 10UL) / ((msid -> msid_Period) * (TICK_FREQ / (msid -> msid_TicksPerFrame)) * 2UL);
  622.  
  623.                               SetDTAttrs( o, NULL, NULL, ADTA_Sample,       (msid -> msid_Sample),
  624.                                                          ADTA_SampleLength, (msid -> msid_SamplesPerFrame),
  625.                                                          ADTA_Period,       (msid -> msid_Period),
  626.                                                          ADTA_Volume,       volume,
  627.                                                          TAG_DONE );
  628.                                                          
  629.                               success = TRUE;
  630.                             }
  631.                             else
  632.                             {
  633.                               /* NewDTObjectA failed */
  634.                               error = IoErr();
  635.                             }
  636.                           }
  637.                           else
  638.                           {
  639.                             /* No audio lock */
  640.                             error = IoErr();
  641.                           }
  642.                         }
  643.                         else
  644.                         {
  645.                           /* no palette memory */
  646.                           error = ERROR_NO_FREE_STORE;
  647.                         }
  648.                       }
  649.                       else
  650.                       {
  651.                         /* We did not get all attributes we need... */
  652.                         error = ERROR_OBJECT_WRONG_TYPE;
  653.                       }
  654.                     }
  655.                   }
  656.                   else
  657.                   {
  658.                     /* We did not get all attributes we need... */
  659.                     error = ERROR_OBJECT_WRONG_TYPE;
  660.                   }
  661.                 }
  662.                 else
  663.                 {
  664.                   /* NewDTObject failed */
  665.                   error = IoErr();
  666.                 }
  667.               }
  668.               else
  669.               {
  670.                 /* no video stream lock */
  671.                 error = IoErr();
  672.               }
  673.             }
  674.             else
  675.             {
  676.               /* demuxer failed */
  677.               error = msid -> Demux . retval2;
  678.             }
  679.           }
  680.           else
  681.           {
  682.             /* No file handle ? - Be sure we got a DTST_RAM sourcetype */
  683.             if( sourcetype == DTST_RAM )
  684.             {
  685.               success = TRUE;
  686.             }
  687.             else
  688.             {
  689.               /* No handle ! */
  690.               error = ERROR_REQUIRED_ARG_MISSING;
  691.             }
  692.           }
  693.         }
  694.       }
  695.       else
  696.       {
  697.         /* can't get required attributes from superclass */
  698.         error = ERROR_OBJECT_WRONG_TYPE;
  699.       }
  700.     }
  701.     else
  702.     {
  703.       /* no memory pool */
  704.       error = ERROR_NO_FREE_STORE;
  705.     }
  706.  
  707.     SetIoErr( error );
  708.  
  709.     return( success );
  710. }
  711.  
  712.  
  713. /*****************************************************************************/
  714.  
  715.  
  716. void OpenLogfile( struct ClassBase *cb, struct MPEGSystemInstData *msid )
  717. {
  718.     if( ((msid -> msid_VerboseOutput) == NULL) || ((msid -> msid_VerboseOutput) == -1L) )
  719.     {
  720.       STRPTR confile;
  721.  
  722.       if( confile = (STRPTR)AllocVec( (((msid -> msid_ProjectName)?(strlen( (msid -> msid_ProjectName) )):(0UL)) + 100UL), MEMF_PUBLIC ) )
  723.       {
  724.         mysprintf( cb, confile, "CON:////MPEG System DataType %s/auto/wait/close/inactive",
  725.                    ((msid -> msid_ProjectName)?(FilePart( (msid -> msid_ProjectName) )):(NULL)) );
  726.  
  727.         msid -> msid_VerboseOutput = Open( confile, MODE_READWRITE );
  728.  
  729.         FreeVec( confile );
  730.       }
  731.     }
  732. }
  733.  
  734.  
  735. static
  736. void mysprintf( struct ClassBase *cb, STRPTR buffer, STRPTR fmt, ... )
  737. {
  738.     APTR args;
  739.  
  740.     args = (APTR)((&fmt) + 1);
  741.  
  742.     RawDoFmt( fmt, args, (void (*))"\x16\xc0\x4e\x75", buffer );
  743. }
  744.  
  745.  
  746. void error_printf( struct ClassBase *cb, struct MPEGSystemInstData *msid, STRPTR format, ... )
  747. {
  748.     OpenLogfile( cb, msid );
  749.  
  750.     if( (msid -> msid_VerboseOutput) && ((msid -> msid_VerboseOutput) != -1L) )
  751.     {
  752.       VFPrintf( (msid -> msid_VerboseOutput), format, (APTR)((&format) + 1) );
  753.     }
  754. }
  755.  
  756.  
  757. void syntax_printf( struct ClassBase *cb, struct MPEGSystemInstData *msid, STRPTR format, ... )
  758. {
  759.     if( msid -> msid_DoSyntax )
  760.     {
  761.       OpenLogfile( cb, msid );
  762.  
  763.       if( (msid -> msid_VerboseOutput) && ((msid -> msid_VerboseOutput) != -1L) )
  764.       {
  765.         VFPrintf( (msid -> msid_VerboseOutput), format, (APTR)((&format) + 1) );
  766.       }
  767.     }
  768. }
  769.  
  770.  
  771. void debug_printf( struct ClassBase *cb, struct MPEGSystemInstData *msid, STRPTR format, ... )
  772. {
  773.     if( msid -> msid_DoDebug )
  774.     {
  775.       OpenLogfile( cb, msid );
  776.  
  777.       if( (msid -> msid_VerboseOutput) && ((msid -> msid_VerboseOutput) != -1L) )
  778.       {
  779.         VFPrintf( (msid -> msid_VerboseOutput), format, (APTR)((&format) + 1) );
  780.       }
  781.     }
  782. }
  783.  
  784.  
  785. void verbose_printf( struct ClassBase *cb, struct MPEGSystemInstData *msid, STRPTR format, ... )
  786. {
  787.     if( (msid -> msid_VerboseOutput) && ((msid -> msid_VerboseOutput) != -1L) )
  788.     {
  789.       VFPrintf( (msid -> msid_VerboseOutput), format, (APTR)((&format) + 1) );
  790.     }
  791. }
  792.  
  793.  
  794. static
  795. ULONG SaveMPEGSystem( struct ClassBase *cb, struct IClass *cl, Object *o, struct dtWrite *dtw )
  796. {
  797.     ULONG retval = 0UL;
  798.     LONG  error  /*= 0L*/;
  799.  
  800. #ifdef HAS_ENCODER
  801.     /* A NULL file handle is a nop (GMultiView uses this to test if a datatype supports RAW writing) */
  802.     if( dtw -> dtw_FileHandle )
  803.     {
  804.       struct MPEGSystemInstData *msid = (struct MPEGSystemInstData *)INST_DATA( cl, o );
  805.  
  806.       ULONG                modeid;
  807.       ULONG               *cregs;
  808.       ULONG                numcolors;
  809.       ULONG                startframe = 0UL,
  810.                            numframes  = 0UL,
  811.                            framestep  = 1UL;
  812.       ULONG                fps        = 0UL;
  813.       struct BitMap       *keyframe;
  814.       ULONG                animwidth,
  815.                            animheight,
  816.                            animdepth;
  817.  
  818.       if( GetDTAttrs( o, ADTA_ModeID,           (&modeid),
  819.                          ADTA_CRegs,            (&cregs),
  820.                          ADTA_NumColors,        (&numcolors),
  821.                          ADTA_Width,            (&animwidth),
  822.                          ADTA_Height,           (&animheight),
  823.                          ADTA_Depth,            (&animdepth),
  824.                          ADTA_Frame,            (&startframe),
  825.                          ADTA_Frames,           (&numframes),
  826.                          ADTA_FramesPerSecond,  (&fps),
  827.                          ADTA_KeyFrame,         (&keyframe),
  828.                          TAG_DONE ) == 10UL )
  829.       {
  830.         struct TagItem     *tstate,
  831.                            *ti;
  832.  
  833.         numframes -= startframe;
  834.  
  835.         tstate = dtw -> dtw_AttrList;
  836.  
  837.         while( ti = NextTagItem( (&tstate) ) )
  838.         {
  839.           switch( ti -> ti_Tag )
  840.           {
  841.             case ADTA_Frame:            startframe = ti -> ti_Data; break;
  842.             case ADTA_Frames:           numframes  = ti -> ti_Data; break;
  843.             case ADTA_FrameIncrement:   framestep  = ti -> ti_Data; break;
  844.           }
  845.         }
  846.  
  847.         if( framestep == 0UL ) framestep = 1UL;
  848.  
  849.         verbose_printf( cb, msid, "saving mpeg system movie %lu %lu %lu\n", startframe, numframes, framestep );
  850.  
  851.         /* here should follow the encoder part... */
  852.       }
  853.       else
  854.       {
  855.         error_printf( cb, msid, "not enougth attributes\n" );
  856.       }
  857.     }
  858. #else
  859.     error = ERROR_NOT_IMPLEMENTED; /* no encoder yet */
  860. #endif /* HAS_ENCODER */
  861.  
  862.     SetIoErr( error );
  863.  
  864.     return( retval );
  865. }
  866.  
  867. /*****************************************************************************/
  868.  
  869. static
  870. UBYTE *get_buf_data( struct ClassBase *cb, struct MPEGSystemInstData *msid, long read_len )
  871. {
  872.     long   len_left;
  873.     long   len_read;
  874.     long   temp1;
  875.     UBYTE *buf_ptr;
  876.  
  877.     /* Calculate how much data is left in the buffer */
  878.     len_left = (msid -> Demux . raw_data_buf_len) - ((msid -> Demux . raw_data_buf_ptr) - (msid -> Demux . raw_data_buf));
  879.  
  880.     /* Not enough for the calling function's needs */
  881.     if( len_left < read_len )
  882.     {
  883.       /* There is some data left, so copy to start of buffer  */
  884.       if( len_left > 0 )
  885.       {
  886.         memcpy( (msid -> Demux . raw_data_buf), (msid -> Demux . raw_data_buf_ptr), (size_t)len_left );
  887.       }
  888.  
  889.       msid -> Demux . raw_data_buf_ptr = &msid -> Demux . raw_data_buf[ 0 ];
  890.  
  891.       temp1 = MAX_DATA_BUF_LEN - len_left;  /* To fill the rest of the buffer */
  892.  
  893.       /* block pos */
  894.       msid -> Demux . curr_file_pos = msid -> Demux . fdin_pos; /* Get file pos */
  895.  
  896.       msid -> Demux . curr_file_pos_in_buffer = ((msid -> Demux . raw_data_buf_ptr) + len_left);
  897.  
  898.       debug_printf( cb, msid, "read: %ld, len %ld, left %ld\n", (LONG)(msid -> Demux . curr_file_pos), (LONG)temp1, (LONG)len_left );
  899.  
  900.       len_read = Read( (msid -> Demux . fdin), (msid -> Demux . curr_file_pos_in_buffer), (LONG)temp1 );
  901.  
  902.       if( len_read == -1L )
  903.       {
  904.         LONG err = IoErr();
  905.  
  906.         error_printf( cb, msid, "Error: reading system file\n" );
  907.         exitdemux( cb, msid, RETURN_FAIL, err );
  908.       }
  909.       else
  910.       {
  911.         msid -> Demux . fdin_pos += len_read;
  912.       }
  913.  
  914.       /* no data left in file - data should never have been requested */
  915.       if( len_read == 0 )
  916.       {
  917.         error_printf( cb, msid, "Error: reached EOF, requested %ld bytes\n", temp1 );
  918.         exitdemux( cb, msid, RETURN_FAIL, DTERROR_NOT_ENOUGH_DATA );
  919.       }
  920.  
  921.       msid -> Demux . raw_data_buf_len = len_left + len_read;
  922.  
  923.       /* Read done to end of file but still not enough data to complete request */
  924.       if( (msid -> Demux . raw_data_buf_len) < read_len )
  925.       {
  926.         error_printf( cb, msid, "Error: insufficient data for read\n" );
  927.         exitdemux( cb, msid, RETURN_FAIL, DTERROR_NOT_ENOUGH_DATA );
  928.       }
  929.     }
  930.  
  931.     buf_ptr                           = msid -> Demux . raw_data_buf_ptr; /* For return to calling function.       */
  932.     msid -> Demux . raw_data_buf_ptr += read_len;                         /* Global advanced for use at next call. */
  933.  
  934.     return( buf_ptr );
  935. }
  936.  
  937.  
  938. static
  939. UBYTE *calc_time_stamp( struct ClassBase *cb, struct MPEGSystemInstData *msid, UBYTE *buf_ptr, long *time_stamp )
  940. {
  941.     /* Determine Time Stamp
  942.      * Contents:
  943.      * Byte  0: 4 bits: depend on SCR/PTS/DTS
  944.      *          3 bits: Time32..30,
  945.      *          1 bit marker:1
  946.      * Byte  1: 8 bits Time29..22.
  947.      * Byte  2: 7 bits Time21..15,
  948.      *          1 bit marker
  949.      * Byte  3: 8 bits Time14..7.
  950.      * Byte  4: 7 bits Time6..0,
  951.      *          1 bit marker
  952.      */
  953.  
  954.     *time_stamp = ((((long)(*buf_ptr)) & 0x0E) << 29);
  955.  
  956.     /* Marker_bit check */
  957.     if( (*buf_ptr & (UBYTE)0x01) != (UBYTE)0x01 )
  958.     {
  959.       syntax_printf( cb, msid, "Expecting marker_bit value '1' at calc_time_stamp A.\n" );
  960.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  961.     }
  962.  
  963.     buf_ptr++;
  964.  
  965.     *time_stamp |= ((((long)(*buf_ptr)) & 0xFF) << 22);
  966.     buf_ptr++;
  967.  
  968.     *time_stamp |= ((((long)(*buf_ptr)) & 0xFE) << 14);
  969.  
  970.     /* Marker_bit check */
  971.     if( (*buf_ptr & (UBYTE)0x01) != (UBYTE)0x01 )
  972.     {
  973.       syntax_printf( cb, msid, "Expecting marker_bit value '1' at calc_time_stamp B.\n" );
  974.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  975.     }
  976.  
  977.     buf_ptr++;
  978.  
  979.     *time_stamp |= ((((long)(*buf_ptr)) & 0xFF) <<  7);
  980.     buf_ptr++;
  981.  
  982.     *time_stamp |= ((((long)(*buf_ptr)) & 0xFE) >>  1);
  983.  
  984.     /* Marker_bit check */
  985.     if( (*buf_ptr & (UBYTE)0x01) != (UBYTE)0x01 )
  986.     {
  987.       syntax_printf( cb, msid, "Expecting marker_bit value '1' at calc_time_stamp C.\n" );
  988.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  989.     }
  990.  
  991.     buf_ptr++;
  992.  
  993.     return( buf_ptr );
  994. }
  995.  
  996.  
  997. static
  998. UBYTE get_next_start_code( struct ClassBase *cb, struct MPEGSystemInstData *msid )
  999. {
  1000.     UBYTE *buf_ptr = NULL; /* dead assignment, but avoids SAS/C "Warning 317: possibly uninitialized variable" */
  1001.     UWORD  zeros;
  1002.  
  1003.     /* Scan for start code; should be hex 00 00 01 for Pack Start Code,
  1004.      * System Start Code, Packet Start Code or ISO_11172_end_code.
  1005.      * Leading zeros are ignored.
  1006.      */
  1007.     for( ;; )
  1008.     {
  1009.       zeros = 0;
  1010.  
  1011.       for( ;; )
  1012.       {
  1013.         buf_ptr = get_buf_data( cb, msid, 1 );
  1014.  
  1015.         if( *buf_ptr == 0x00 )
  1016.         {
  1017.           zeros++;
  1018.         }
  1019.         else
  1020.         {
  1021.           if( zeros >= 2 )
  1022.           {
  1023.             if( *buf_ptr != 0x01 )
  1024.             {
  1025.               zeros = 0;
  1026.             }
  1027.             else
  1028.             {
  1029.               break;
  1030.             }
  1031.           }
  1032.         }
  1033.       }
  1034.  
  1035.       buf_ptr = get_buf_data( cb, msid, 1 );
  1036.  
  1037.       if( (msid -> Demux . system_found) || (*buf_ptr == 0xBB) )
  1038.       {
  1039.         break;
  1040.       }
  1041.     }
  1042.     
  1043.     switch( *buf_ptr )
  1044.     {
  1045.       case (UBYTE)0xB9:
  1046.           return( (UBYTE)ISO_11172_END_CODE );
  1047.  
  1048.       case (UBYTE)0xBA:
  1049.           return( (UBYTE)PACK_START_CODE );
  1050.  
  1051.       case (UBYTE)0xBB:
  1052.       {
  1053.           msid -> Demux . system_found = TRUE;
  1054.           verbose_printf( cb, msid, "system start\n" );
  1055.  
  1056.           return( (UBYTE)SYSTEM_START_CODE );
  1057.       }
  1058.     }
  1059.  
  1060.     return( *buf_ptr );  /* It must be a stream_id. */
  1061. }
  1062.  
  1063.  
  1064. static
  1065. void read_pack_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACK_header *pki )
  1066. {
  1067.     UBYTE *buf_ptr;
  1068.  
  1069.     pki -> SCR = 0;
  1070.  
  1071.     buf_ptr = get_buf_data( cb, msid, PACK_HEADER_LENGTH );
  1072.  
  1073.     /* Determine System Clock Reference (SCR)
  1074.      * Check marker_bits: '0010' = 0x2
  1075.      */
  1076.  
  1077.     if( (*buf_ptr & (UBYTE)0xF0) != (UBYTE)0x20 )
  1078.     {
  1079.       syntax_printf( cb, msid, "Expecting '0010' after pack_start_code.\n" );
  1080.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1081.     }
  1082.  
  1083.     buf_ptr = calc_time_stamp( cb, msid, buf_ptr, (&(pki -> SCR)) );
  1084.  
  1085.     /* Determine Mux Rate
  1086.      * Contents:
  1087.      * Byte 5: 1 bit marker,
  1088.      *         7 bits mux_rate.
  1089.      * Byte 6: 8 bits mux_rate.
  1090.      * Byte 7: 7 bits mux_rate,
  1091.      *         1 bit marker
  1092.      */
  1093.     pki -> mux_rate = ((((long)(*buf_ptr)) & 0x7F) << 14);
  1094.  
  1095.     /* Marker_bit check */
  1096.     if( (*buf_ptr & (UBYTE)0x80) != (UBYTE)0x80 )
  1097.     {
  1098.       syntax_printf( cb, msid, "byte= %lx.\n", *buf_ptr );
  1099.       syntax_printf( cb, msid, "Expecting marker_bit value '1' at read_pack_header A.\n" );
  1100.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1101.     }
  1102.  
  1103.     buf_ptr++;
  1104.  
  1105.     pki -> mux_rate |= ((((long)(*buf_ptr)) & 0xFF) << 7);
  1106.     buf_ptr++;
  1107.  
  1108.     pki -> mux_rate |= ((((long)(*buf_ptr)) & 0xFE) >> 1);
  1109.  
  1110.     /* Marker_bit check */
  1111.     if( (*buf_ptr & (UBYTE)0x01) != (UBYTE)0x01 )
  1112.     {
  1113.       syntax_printf( cb, msid, "Expecting marker_bit value '1' at read_pack_header B.\n" );
  1114.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1115.     }
  1116. }
  1117.  
  1118.  
  1119. static
  1120. void read_system_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, SYSTEM_header *si )
  1121. {
  1122.     UBYTE *buf_ptr;
  1123.     long   j;
  1124.     UBYTE  test;
  1125.  
  1126.     /* Read System Header Length: 2 Bytes after start code.
  1127.      * Length of header after header length bytes.
  1128.      * Bytes  0 & 1: 8 bits header_length--high & low
  1129.      */
  1130.     buf_ptr = get_buf_data( cb, msid, 2 );
  1131.     si -> header_length  = (ULONG)(((long)(*buf_ptr)) << 8);
  1132.     buf_ptr++;
  1133.     si -> header_length |= (ULONG)(((long)(*buf_ptr)) & 0xFF);
  1134.  
  1135.     /* Read the rest of the header */
  1136.     buf_ptr = get_buf_data( cb, msid, (si -> header_length) );
  1137.  
  1138.     /* Byte  0: 1 bit marker, 
  1139.      *          7 bits rate_bound--high
  1140.      */
  1141.     si -> rate_bound  = (ULONG)((((long)*buf_ptr) & 0x7F) << 15);
  1142.  
  1143.     /* Marker bit check */
  1144.     if( (*buf_ptr & (UBYTE)0x80) != (UBYTE)0x80 )
  1145.     {
  1146.       syntax_printf( cb, msid, "Expecting marker_bit value '1' before rate_bound--high.\n" );
  1147.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1148.     }
  1149.  
  1150.     buf_ptr++;
  1151.  
  1152.     /* Byte  1: 8 bits rate_bound--mid */
  1153.     si -> rate_bound += (ULONG)((((long)*buf_ptr) & 0xFF) << 7);
  1154.     buf_ptr++;
  1155.  
  1156.     /* Byte  2: 7 bits rate_bound-low,
  1157.      *          1 bit marker
  1158.      */
  1159.     si -> rate_bound += (ULONG)((((long)*buf_ptr) & 0xFE) >>  1);
  1160.  
  1161.     /* Marker bit check */
  1162.     if( (*buf_ptr & (UBYTE)0x01) != (UBYTE)0x01 )
  1163.     {
  1164.       syntax_printf( cb, msid, "Expecting marker_bit value '1' after rate_bound.\n" );
  1165.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1166.     }
  1167.  
  1168.     buf_ptr++;
  1169.  
  1170.     /* Byte  3: 6 bits audio_bound, 
  1171.      * 1 bit fixed_flag,
  1172.      * 1bit CSPS_flag 
  1173.      */
  1174.     si -> audio_bound = (ULONG)((((long)*buf_ptr) & 0xFF) >> 2);
  1175.     si -> fixed_flag  =  (BOOL)((((long)*buf_ptr) & 0x02) >> 1);
  1176.     si -> CSPS_flag   =  (BOOL) (((long)*buf_ptr) & 0x01);
  1177.     buf_ptr++;
  1178.  
  1179.     /* Byte 4: 1b system_audio_lock_flag,
  1180.      *         1b system_video_lock_flag,
  1181.      *         1b marker,
  1182.      *         5b video_bound
  1183.      */
  1184.     si -> system_audio_lock_flag =  (BOOL)((((long)*buf_ptr) & 0x80) >> 7);
  1185.     si -> system_video_lock_flag =  (BOOL)((((long)*buf_ptr) & 0x40) >> 6);
  1186.     si -> video_bound            = (ULONG) (((long)*buf_ptr) & 0x1F);
  1187.  
  1188.     /* Marker bit check */
  1189.     if( (*buf_ptr & (UBYTE)0x20) != (UBYTE)0x20 )
  1190.     {
  1191.       syntax_printf( cb, msid, "Expecting marker_bit value '1' after system_video_lock_flag.\n" );
  1192.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1193.     }
  1194.  
  1195.     buf_ptr++;
  1196.  
  1197.     if( *buf_ptr != (UBYTE)0xFF )
  1198.     {
  1199.       syntax_printf( cb, msid, "Reserved byte not set to default\n" );
  1200.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1201.     }
  1202.  
  1203.     buf_ptr++;
  1204.  
  1205.     if( (si -> header_length) == 6 )
  1206.     {
  1207.       return;
  1208.     }
  1209.  
  1210.     j = 0;
  1211.  
  1212.     while( (ULONG)buf_ptr < (ULONG)(msid -> Demux . raw_data_buf_ptr) )
  1213.     {
  1214.       /* All lmntry stream_id's ... */
  1215.       test = (*buf_ptr & (UBYTE)0x80);
  1216.  
  1217.       if( test == 0 )
  1218.       {
  1219.         error_printf( cb, msid, "system header length incorrect\n" );
  1220.         exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1221.       }
  1222.  
  1223.       si -> STD_buffer_info[ j ] . stream_id = (*buf_ptr & (UBYTE)0xFF);
  1224.  
  1225.       buf_ptr++;
  1226.  
  1227.       /* Check marker_bits */
  1228.       if( (*buf_ptr & (UBYTE)0xC0) != (UBYTE)0xC0 )
  1229.       {
  1230.         syntax_printf( cb, msid, "Expecting placeholder bit values '11' after stream_id.\n" );
  1231.         exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1232.       }
  1233.  
  1234.       si -> STD_buffer_info[ j ] . STD_buffer_bound_scale = (*buf_ptr & (UBYTE)0x20) >> 5;
  1235.       si -> STD_buffer_info[ j ] . STD_buffer_size_bound  = (*buf_ptr & (UBYTE)0x1F) << 8;
  1236.  
  1237.       buf_ptr++;
  1238.  
  1239.       si -> STD_buffer_info[ j ] . STD_buffer_size_bound  |= *buf_ptr & (UBYTE)0xFF;
  1240.  
  1241.       buf_ptr++;
  1242.  
  1243.       j++;
  1244.     }
  1245. }
  1246.  
  1247.  
  1248. static
  1249. void read_packet_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACKET_header *pi )
  1250. {
  1251.     UBYTE *buf_ptr;
  1252.     UBYTE  test,
  1253.            test1;
  1254.     long   i;
  1255.  
  1256.     pi -> PTS = 0;
  1257.     pi -> DTS = 0;
  1258.  
  1259.     /* read packet length */
  1260.     buf_ptr = get_buf_data( cb, msid, 2 );
  1261.  
  1262.     /* Bytes 0 & 1: 8 bits packet_length -- high & low */
  1263.     pi -> packetlength  = (ULONG)(((long)*buf_ptr) << 8);
  1264.     buf_ptr++;
  1265.     pi -> packetlength |= (ULONG)(((long)*buf_ptr) & 0xFF);
  1266.  
  1267.     /* Get the remainder of the packet. */
  1268.     buf_ptr = get_buf_data( cb, msid, (pi -> packetlength) );
  1269.  
  1270.     /* private stream 2 */
  1271.     if( (pi -> stream_id) <= (UBYTE)0xBF )
  1272.     {
  1273.       pi -> packet_ptr = buf_ptr;
  1274.       return;
  1275.     }
  1276.  
  1277.     /* Skip over any stuffing Bytes 1111 1111 (16 max)
  1278.      * Count to 17 to see if there are more than allowed in the spec.
  1279.      */
  1280.  
  1281.     i = 0;
  1282.  
  1283.     while( (*buf_ptr == (UBYTE)0xFF) && (i < 17) )
  1284.     {
  1285.       buf_ptr++;
  1286.       pi -> packetlength--;
  1287.       i++;
  1288.     }
  1289.  
  1290.     if( i == 17 )
  1291.     {
  1292.       error_printf( cb, msid, "Too many stuffing bytes after packet_length\n" );
  1293.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1294.     }
  1295.  
  1296.     /* If nextbits =='01' read STD_buffer_scale & _size
  1297.      * Byte: 2b '01',
  1298.      *       1b STD_buffer_scale,
  1299.      *       5b STD_buffer_size-hi
  1300.      * Byte: 8 bits STD_buffer_size--lo
  1301.      */
  1302.     test1 = *buf_ptr & (UBYTE)0xC0;
  1303.  
  1304.     if( test1 == (UBYTE)0x40 )
  1305.     {
  1306.      /* read STD values */
  1307.       pi -> STD_buffer_scale = (*buf_ptr & (UBYTE)0x20) >> 5;
  1308.       pi -> STD_buffer_size  = (*buf_ptr & (UBYTE)0x1F) << 8;
  1309.       buf_ptr++;
  1310.  
  1311.       pi -> packetlength--;
  1312.       pi -> STD_buffer_size |= (*buf_ptr & (UBYTE)0xFF);
  1313.       buf_ptr++;
  1314.  
  1315.       pi -> packetlength--;
  1316.     }
  1317.  
  1318.     /* Determine whether to read in PTS, PTS & DTS, or neither before data. */
  1319.     test = (*buf_ptr & (UBYTE)0xF0);
  1320.  
  1321.     switch( test )
  1322.     {
  1323.       case (UBYTE)0x20:   /* Get PTS only */
  1324.       {
  1325.           buf_ptr = calc_time_stamp( cb, msid, buf_ptr, (&(pi -> PTS)) );
  1326.           pi -> packetlength -= 5;
  1327.       }
  1328.           break;
  1329.  
  1330.       case (UBYTE)0x30:   /* Get PTS & DTS. Both same format as PTS above.
  1331.                            * pts and data
  1332.                            */
  1333.       {
  1334.           buf_ptr = calc_time_stamp( cb, msid, buf_ptr, (&(pi -> PTS)) );
  1335.  
  1336.           /* Get DTS */
  1337.           if( (*buf_ptr & (UBYTE)0xF0) != (UBYTE)0x10 )
  1338.           {
  1339.             syntax_printf( cb, msid, "Expecting bits '0001' before DTS in read_packet_header\n" );
  1340.             exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1341.           }
  1342.  
  1343.           buf_ptr = calc_time_stamp( cb, msid, buf_ptr, (&(pi -> DTS)) );
  1344.           pi -> packetlength -= 10;
  1345.       }
  1346.           break;
  1347.  
  1348.       case (UBYTE)0x00:
  1349.       {
  1350.           if( *buf_ptr != (UBYTE)0x0F )
  1351.           {
  1352.             error_printf( cb, msid, "not a valid packet time sequence\n" );
  1353.             exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1354.           }
  1355.  
  1356.           buf_ptr++;
  1357.           pi -> packetlength--;
  1358.       }
  1359.           break;
  1360.  
  1361.       default:
  1362.       {
  1363.           error_printf( cb, msid, "invalid time code in packet\n" );
  1364.           exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1365.       }
  1366.           break;
  1367.     }
  1368.  
  1369.     /* packetlength should have been properly set by the above */
  1370.  
  1371.     pi -> packet_ptr = buf_ptr;
  1372. }
  1373.  
  1374.  
  1375. static
  1376. void print_pack_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACK_header *pki )
  1377. {
  1378.     long mux_byte_rate = (pki -> mux_rate) * 50;
  1379.  
  1380.     verbose_printf( cb, msid, "PACK HEADER: SCR = %ld, Mux Rate = %ld, or %ld Bytes per second\n",
  1381.                     (LONG)(pki -> SCR), (LONG)(pki -> mux_rate), mux_byte_rate );
  1382. }
  1383.  
  1384.  
  1385. static
  1386. void print_system_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, SYSTEM_header *si )
  1387. {
  1388.     long  i            = 0;
  1389.     long  stream_num   = 0;
  1390.     long  buf_byte_size_bound;
  1391.     UBYTE stream_type  = 0;
  1392.  
  1393.     verbose_printf( cb, msid, "SYSTEM HEADER: Hdr Len = %ld, Rate bound = %ld, Audio bound = %ld,\n",
  1394.                     (LONG)(si -> header_length),
  1395.                     (LONG)(si -> rate_bound),
  1396.                     (LONG)(si -> audio_bound) );
  1397.  
  1398.     verbose_printf( cb, msid, "Fixed flag = %ld, CSPS flag = %ld, Sys audio lock flag = %ld,\n",
  1399.              (LONG)(si -> fixed_flag),
  1400.              (LONG)(si -> CSPS_flag),
  1401.              (LONG)(si -> system_audio_lock_flag) );
  1402.  
  1403.     verbose_printf( cb, msid, "Sys video lock flag = %ld, Video bound = %ld\n",
  1404.             (LONG)(si -> system_video_lock_flag), (LONG)(si -> video_bound) );
  1405.  
  1406.     while( si -> STD_buffer_info[ i ] . stream_id != 0 )
  1407.     {
  1408.       if( ((si -> STD_buffer_info[ i ] . stream_id >> 5) & 0x6) == 0x6 )
  1409.       {
  1410.         stream_type = 'A';
  1411.         stream_num  = (long)((si -> STD_buffer_info[ i ] . stream_id) & 0x1F);
  1412.       }
  1413.  
  1414.       if( ((si -> STD_buffer_info[ i ] . stream_id >> 4) & 0xE) == 0xE )
  1415.       {
  1416.         stream_type = 'V';
  1417.         stream_num  = (long)((si -> STD_buffer_info[ i]  . stream_id) & 0x0F);
  1418.       }
  1419.  
  1420.       if( si -> STD_buffer_info[ i ] . STD_buffer_bound_scale == 0 )
  1421.       {
  1422.         buf_byte_size_bound = si -> STD_buffer_info[ i ] . STD_buffer_size_bound * 128;
  1423.       }
  1424.       else
  1425.       {
  1426.         buf_byte_size_bound= si -> STD_buffer_info[ i ] . STD_buffer_size_bound * 1024;
  1427.       }
  1428.  
  1429.       verbose_printf( cb, msid, "STD buf %ld: Stream %lc%ld, Buf bound scale %ld, Buf size bound %ld or %ld bytes\n",
  1430.               i, stream_type, stream_num,
  1431.               (si -> STD_buffer_info[ i ] . STD_buffer_bound_scale),
  1432.               (si -> STD_buffer_info[ i ] . STD_buffer_size_bound),
  1433.               buf_byte_size_bound );
  1434.       i++;
  1435.     }
  1436. }
  1437.  
  1438.  
  1439. static
  1440. void print_packet_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACKET_header *pi )
  1441. {
  1442.     long   stream_num  = 0;
  1443.     UBYTE  stream_type = 0;
  1444.  
  1445.     if( ((pi -> stream_id >> 5) & 0x6) == 0x6 )
  1446.     {
  1447.       stream_type = 'A';
  1448.       stream_num = (long)((pi -> stream_id) & 0x1F);
  1449.     }
  1450.  
  1451.     if( ((pi -> stream_id >> 4) & 0xE) == 0xE )
  1452.     {
  1453.       stream_type = 'V';
  1454.       stream_num = (long)((pi -> stream_id) & 0x0F);
  1455.     }
  1456.  
  1457.     verbose_printf( cb, msid, "PACKET HDR %lc%ld: %ldB, STD buf scale %ld, ..size %ld, PTS %ld, DTS %ld\n",
  1458.             stream_type,
  1459.             stream_num,
  1460.             (pi -> packetlength),
  1461.             (pi -> STD_buffer_scale),
  1462.             (pi -> STD_buffer_size),
  1463.             (pi -> PTS),
  1464.             (pi -> DTS) );
  1465. }
  1466.  
  1467.  
  1468. static
  1469. void demux( struct ClassBase *cb, struct MPEGSystemInstData *msid, BPTR file )
  1470. {
  1471.     PACK_header    pack_info;
  1472.     PACK_header   *pack_info_p = &pack_info;
  1473.     SYSTEM_header  sys_info;
  1474.     SYSTEM_header *sys_info_p  = &sys_info;
  1475.     PACKET_header  pkt_info;
  1476.     PACKET_header *pkt_info_p  = &pkt_info;
  1477.  
  1478.     long           i,
  1479.                    j;
  1480.     long           current_audio = 0;
  1481.     long           current_video = 0;
  1482.     long           demux_id[ MAX_MPEG_STREAMS ];
  1483.     UBYTE          next_code;
  1484.  
  1485.     /* Alloc input buffer */
  1486.     if( msid -> Demux . raw_data_buf = (UBYTE *)AllocVec( MAX_DATA_BUF_LEN, MEMF_PUBLIC ) )
  1487.     {
  1488.       /* Set "point of return" on decoder exit/error */
  1489.       if( setjmp( (msid -> Demux . exit_buf) ) == 0 )
  1490.       {
  1491.         /* Init remaining fields */
  1492.         msid -> Demux . raw_data_buf_len = 0;
  1493.         msid -> Demux . raw_data_buf_ptr = msid -> Demux . raw_data_buf;
  1494.  
  1495.         msid -> Demux . fdin     = file;
  1496.         msid -> Demux . fdin_pos = 0L;
  1497.  
  1498.         /* Read and write data. */
  1499.         for( ;; )
  1500.         {
  1501.           next_code = get_next_start_code( cb, msid );
  1502.  
  1503.           verbose_printf( cb, msid, "next_code = %lx\n", (LONG)next_code );
  1504.  
  1505.           /* next_code identifies whether the stream is at
  1506.            *  the beginning of a system stream, a pack, or a packet,
  1507.            *  or if it is at the end of a system stream.
  1508.            */
  1509.           switch( next_code )
  1510.           {
  1511.             case ((UBYTE)PACK_START_CODE):      /* 0xBA */
  1512.             {
  1513.                 read_pack_header( cb, msid, pack_info_p );
  1514.                 print_pack_header( cb, msid, pack_info_p );
  1515.             }
  1516.                 break;
  1517.  
  1518.             case ((UBYTE)SYSTEM_START_CODE):      /* 0xBB */
  1519.             {
  1520.                 read_system_header( cb, msid, sys_info_p );
  1521.                 print_system_header( cb, msid, sys_info_p );
  1522.  
  1523.                 msid -> Demux . N = sys_info_p -> audio_bound;
  1524.                 msid -> Demux . M = sys_info_p -> video_bound;
  1525.  
  1526.                 verbose_printf( cb, msid, " %ld audio, %ld video\n", (msid -> Demux . N), (msid -> Demux . M) );
  1527.  
  1528.                 current_audio = 0;
  1529.                 current_video = msid -> Demux . N;
  1530.  
  1531.                 for( i = 0 ; i < MAX_MPEG_STREAMS ; i++ )
  1532.                 {
  1533.                   demux_id[ i ] = -1;
  1534.                 }
  1535.             }
  1536.                 break;
  1537.  
  1538.             case ((UBYTE)ISO_11172_END_CODE):      /* 0xB9 */
  1539.             {
  1540.                 verbose_printf( cb, msid, "end of system stream reached\n" );
  1541.  
  1542.                 exitdemux( cb, msid, RETURN_OK, 0L );
  1543.             }
  1544.                 break;
  1545.  
  1546.             default:   /* PACKET START CODE & stream_id */
  1547.             {
  1548.                 pkt_info_p -> stream_id = next_code;
  1549.                 read_packet_header( cb, msid, pkt_info_p );
  1550.                 print_packet_header( cb, msid, pkt_info_p );
  1551.  
  1552.                 /* The stream_id identifies the stream by type and number */
  1553.                 switch( pkt_info_p -> stream_id )
  1554.                 {
  1555.                   case( (UBYTE)0xB8 ): /* may need more work */
  1556.                   {
  1557.                       /* Following STD_buffer_scale and _size refer to
  1558.                        * all audio streams in the muxed stream
  1559.                        */
  1560.                       error_printf( cb, msid, "Error handling common audio STD_buffer_scale and _size.\n" );
  1561.                       exitdemux( cb, msid, RETURN_FAIL, DTERROR_UNKNOWN_COMPRESSION );
  1562.                   }
  1563.                       break;
  1564.  
  1565.                   case( (UBYTE)0xB9 ): /* may need more work */
  1566.                   {
  1567.                       /* Following STD_buffer_scale and _size refer to
  1568.                        * all video streams in the muxed stream
  1569.                        */
  1570.                       error_printf( cb, msid, "Error handling common video STD_buffer_scale and _size.\n" );
  1571.                       exitdemux( cb, msid, RETURN_FAIL, DTERROR_UNKNOWN_COMPRESSION );
  1572.                   }
  1573.                       break;
  1574.  
  1575.                   case( (UBYTE)0xBC ):
  1576.                   {
  1577.                       /* Reserved stream: discard */
  1578.                       error_printf( cb, msid, "Received reserved stream\n" );
  1579.                       exitdemux( cb, msid, RETURN_FAIL, DTERROR_UNKNOWN_COMPRESSION );
  1580.                   }
  1581.                       break;
  1582.  
  1583.                   case( (UBYTE)0xBD ):
  1584.                   {
  1585.                       /* private_stream_1: discard */
  1586.                       error_printf( cb, msid, "Received private_stream_1\n" );
  1587.                       exitdemux( cb, msid, RETURN_FAIL, DTERROR_UNKNOWN_COMPRESSION );
  1588.                   }
  1589.                       break;
  1590.  
  1591.                   case( (UBYTE)0xBE ):  /* data bytes all FF */
  1592.                   {
  1593.                       /* Padding stream: discard */
  1594.                       verbose_printf( cb, msid, "Received padding stream\n" );
  1595.                   }
  1596.                       break;
  1597.  
  1598.                   case( (UBYTE)0xBF ):
  1599.                   {
  1600.                       /* private_stream_2: discard */
  1601.                       error_printf( cb, msid, "Received private_stream_2\n" );
  1602.  
  1603.                       exitdemux( cb, msid, RETURN_FAIL, DTERROR_UNKNOWN_COMPRESSION );
  1604.                   }
  1605.                       break;
  1606.  
  1607.                   default:
  1608.                   {
  1609.                       /* The stream is an audio, video, or reserved_data stream.
  1610.                        * Convert stream_id to C0 to 0, EF to 48
  1611.                        */
  1612.                       i = (((long)pkt_info_p -> stream_id) & 0xFF) - 192;
  1613.  
  1614.                       if( i < 0 )
  1615.                       {
  1616.                         /* Invalid stream: do nothing */
  1617.                       }
  1618.                       else
  1619.                       {
  1620.                         /* Audio or Video stream. */
  1621.                         if( i < 48 )
  1622.                         {
  1623.                           BOOL                isaudio = (i < 32);
  1624.                           struct PacketBlock *pb;
  1625.  
  1626.                           if( demux_id[ i ] == -1 )
  1627.                           {
  1628.                             /* A new stream */
  1629.                             if( isaudio )
  1630.                             {
  1631.                               /* Audio */
  1632.                               demux_id[ i ] = current_audio;
  1633.                               current_audio++;
  1634.                             }
  1635.                             else
  1636.                             {
  1637.                               demux_id[ i ] = current_video;
  1638.                               current_video++;
  1639.                             }
  1640.                           }
  1641.  
  1642.                           j = demux_id[ i ];
  1643.  
  1644.                           /* No file ? - Then create it ! */
  1645.                           if( (msid -> Demux . fd_demuxa[ j ] . sl_handle) == NULL )
  1646.                           {
  1647.                             NewList( (struct List *)(&(msid -> Demux . fd_demuxa[ j ] . sl_packetblocklist)) );
  1648.  
  1649.                             msid -> Demux . fd_demuxa[ j ] . sl_handle = msid -> Demux . fdin;
  1650.                           }
  1651.  
  1652.                           /* block pos */
  1653.                           verbose_printf( cb, msid, "write: off %ld len %ld\n", (msid -> Demux . curr_file_pos +  /* file pos */
  1654.                                           (long)((pkt_info_p -> packet_ptr) - msid -> Demux . curr_file_pos_in_buffer)),
  1655.                                           (pkt_info_p -> packetlength) );
  1656.  
  1657.                           /* Create, fill and queue a PacketBlock node */
  1658.                           pb = (struct PacketBlock *)AllocPooled( (msid -> msid_Pool), (ULONG)sizeof( struct PacketBlock ) );
  1659.                           if( pb == NULL ) exitdemux( cb, msid, RETURN_FAIL, ERROR_NO_FREE_STORE );
  1660.  
  1661.                           pb -> system_offset = (msid -> Demux . curr_file_pos + (long)((pkt_info_p -> packet_ptr) - msid -> Demux . curr_file_pos_in_buffer)); /* file pos */
  1662.                           pb -> length        = (pkt_info_p -> packetlength);
  1663.  
  1664.                           /* Inc stream size */
  1665.                           msid -> Demux . fd_demuxa[ j ] . sl_size += pb -> length;
  1666.  
  1667.                           AddTail( (struct List *)(&(msid -> Demux . fd_demuxa[ j ] . sl_packetblocklist)), (struct Node *)(&(pb -> node)) );
  1668.                         }
  1669.                         else
  1670.                         {
  1671.                           if( i >= 48 )
  1672.                           {
  1673.                             /* It's a reserved data stream.
  1674.                              * Additional functionality will be implementation dependent
  1675.                              */
  1676.                             verbose_printf( cb, msid, "Reserved data stream %ld is being ignored.\n", i );
  1677.                             break;
  1678.                           }
  1679.                           else
  1680.                           {
  1681.                             /* Should never be reached. */
  1682.                             error_printf( cb, msid, "Unrecognized stream ID: %ld %lx %lc\n",
  1683.                                           (pkt_info_p -> stream_id),
  1684.                                           (pkt_info_p -> stream_id),
  1685.                                           (long)(pkt_info_p -> stream_id) );
  1686.  
  1687.                             exitdemux( cb, msid, RETURN_FAIL, DTERROR_UNKNOWN_COMPRESSION );
  1688.                           }
  1689.                         }
  1690.                       }
  1691.                   }
  1692.                       break;
  1693.               }
  1694.             }
  1695.           }
  1696.         }
  1697.       }
  1698.  
  1699.       /* Success ? */
  1700.       if( ((msid -> Demux . retval) <= RETURN_WARN) || (msid -> msid_IgnoreErrors) )
  1701.       {
  1702.         RunHandler( cb, msid );
  1703.       }
  1704.  
  1705.       FreeVec( (msid -> Demux . raw_data_buf) );
  1706.     }
  1707. }
  1708.  
  1709.  
  1710. static
  1711. void exitdemux( struct ClassBase *cb, struct MPEGSystemInstData *msid, LONG result, LONG result2 )
  1712. {
  1713.     msid -> Demux . retval  = result;
  1714.     msid -> Demux . retval2 = result2;
  1715.  
  1716.     longjmp( (msid -> Demux . exit_buf), 1 );
  1717. }
  1718.  
  1719.  
  1720. /*****************************************************************************/
  1721.  
  1722. static
  1723. BPTR GetStreamLock( struct ClassBase *cb, struct MPEGSystemInstData *msid, ULONG num, BOOL isaudio )
  1724. {
  1725.       if( msid -> Handler . Process )
  1726.       {
  1727.         BPTR lock;
  1728.  
  1729.         num += (isaudio)?(0UL):(msid -> Demux . N); /* Add video ID-offset if neccesary */
  1730.  
  1731.         lock = (BPTR)DoPkt( (&(msid -> Handler . Process -> pr_MsgPort)), ACTION_COPY_DIR, MKBADDR( (num * 16) ), 0L, 0L, 0L, 0L );
  1732.  
  1733.         return( lock );
  1734.       }
  1735.  
  1736.       return( NULL );
  1737. }
  1738.  
  1739.  
  1740. static
  1741. void RunHandler( struct ClassBase *cb, struct MPEGSystemInstData *msid )
  1742. {
  1743.     if( msid -> Handler . Process = CreateNewProcTags( NP_Entry,        (ULONG)Handler,
  1744.                                                        NP_Name,         (ULONG)"mpegsystem.datatype (MPEG System Demux Handler)",
  1745.                                                        NP_Priority,     15L,
  1746.                                                        NP_StackSize,    16384UL,
  1747.                                                        TAG_DONE ) )
  1748.     {
  1749.       /* Initialize the message */
  1750.       msid -> Handler . Startup . sm_Message . mn_Node . ln_Type = NT_MESSAGE;
  1751.       msid -> Handler . Startup . sm_Message . mn_Length         = sizeof( struct StartupMsg );
  1752.       msid -> Handler . Startup . sm_CB                          = cb;
  1753.       msid -> Handler . Startup . sm_msid                        = msid;
  1754.  
  1755.       /* Send the information to the process */
  1756.       PutMsg( (&(msid -> Handler . Process -> pr_MsgPort)), (&(msid -> Handler . Startup . sm_Message)) );
  1757.     }
  1758. }
  1759.  
  1760.  
  1761. /* Kill our virtual demux filesystem and wait until it is really dead...
  1762.  * (Should be replaced by a version which uses exec.library/Wait)
  1763.  */
  1764. static
  1765. void KillHandler( struct ClassBase *cb, struct MPEGSystemInstData *msid )
  1766. {
  1767.     while( (msid -> Handler . Process) )
  1768.     {
  1769.       Forbid();
  1770.  
  1771.         if( msid -> Handler . Process )
  1772.         {
  1773.           Signal( (&(msid -> Handler . Process -> pr_Task)), SIGBREAKF_CTRL_C );
  1774.         }
  1775.  
  1776.       Permit();
  1777.  
  1778.       /* Wait a 1/25 sec before trying it again... */
  1779.       Delay( (TICKS_PER_SECOND / 25UL) );
  1780.     }
  1781. }
  1782.  
  1783.  
  1784. /* virtual demux filesystem handler entry */
  1785. DISPATCHERFLAGS
  1786. static
  1787. void Handler( void )
  1788. {
  1789. #ifdef SysBase
  1790. #undef SysBase
  1791. #endif
  1792.     struct ExecBase           *SysBase = (*((struct ExecBase **)4UL));
  1793.     struct Process            *pr;
  1794.     struct StartupMsg         *sm;
  1795.     struct ClassBase          *cb;
  1796.     struct MPEGSystemInstData *msid;
  1797.     ULONG                      sigflags;
  1798.     struct Message            *msg;
  1799.     BOOL                       done = FALSE;
  1800.  
  1801.     /* Find out who we are */
  1802.     pr = (struct Process *)FindTask( NULL );
  1803.  
  1804.     /* Get the startup message */
  1805.     WaitPort( (&(pr -> pr_MsgPort)) );
  1806.     sm = (struct StartupMsg *)GetMsg( (&(pr -> pr_MsgPort)) );
  1807.  
  1808.     /* Pull all the information required from the startup message */
  1809.     cb   = sm -> sm_CB;
  1810.     msid = sm -> sm_msid;
  1811.  
  1812.     /* BUG: The parent process does currently not handle a failure if this process... */
  1813.     while( (msid -> Handler . mp = CreateMsgPort()) == NULL )
  1814.     {
  1815.     }
  1816.  
  1817.     /* Init DOS_STDPKT queue which is used within the handler to avoid a AllocDOSObject
  1818.      * and fill it up with some packets...
  1819.      */
  1820.     {
  1821.       ULONG i;
  1822.  
  1823.       NewList( (struct List *)(&(msid -> Handler . pktpool)) );
  1824.  
  1825.       for( i = 0UL ; i < 16UL ; i++ )
  1826.       {
  1827.         struct DosPacket *dp;
  1828.  
  1829.         if( dp = (struct DosPacket *)AllocDosObject( DOS_STDPKT, NULL ) )
  1830.         {
  1831.           AddTail( (struct List *)(&(msid -> Handler . pktpool)), (&(dp -> dp_Link -> mn_Node)) );
  1832.         }
  1833.         else
  1834.         {
  1835.           break;
  1836.         }
  1837.       }
  1838.     }
  1839.  
  1840.     do
  1841.     {
  1842.       sigflags = Wait( (1UL << (pr -> pr_MsgPort . mp_SigBit)) | SIGBREAKF_CTRL_C );
  1843.  
  1844.       if( sigflags & SIGBREAKF_CTRL_C )
  1845.       {
  1846.         done = TRUE;
  1847.       }
  1848.  
  1849.       while( msg = GetMsg( (&(pr -> pr_MsgPort)) ) )
  1850.       {
  1851.         dispatch_packet( cb, msid, (struct DosPacket *)(msg -> mn_Node . ln_Name) );
  1852.       }
  1853.     } while( (!done) || (msid -> Handler . OpenCount) );
  1854.  
  1855.     /* Free DOS_STDPKT queue */
  1856.     {
  1857.       struct Node *node;
  1858.  
  1859.       while( node = RemHead( (struct List *)(&(msid -> Handler . pktpool)) ) )
  1860.       {
  1861.         struct DosPacket *dp = (struct DosPacket *)(node -> ln_Name);
  1862.  
  1863.         FreeDosObject( DOS_STDPKT, (APTR)dp );
  1864.       }
  1865.     }
  1866.  
  1867.     DeleteMsgPort( (msid -> Handler . mp) );
  1868.  
  1869.     Forbid();
  1870.  
  1871.       msid -> Handler . Process = NULL;
  1872. #define SysBase (cb -> cb_SysBase)
  1873. }
  1874.  
  1875.  
  1876. static
  1877. void dispatch_packet( struct ClassBase *cb, struct MPEGSystemInstData *msid, struct DosPacket *dp )
  1878. {
  1879.     struct MsgPort      *rport;
  1880.     struct StreamHandle *sh;
  1881.  
  1882.     switch( dp -> dp_Type )
  1883.     {
  1884.       case ACTION_FINDINPUT:
  1885.       case ACTION_FH_FROM_LOCK:
  1886.       {
  1887.           struct FileHandle  *fh             = (struct FileHandle  *)BADDR( (dp -> dp_Arg1) );
  1888.           struct FileLock    *fl             = (struct FileLock    *)BADDR( (dp -> dp_Arg2) );
  1889.           LONG                stream_index   = fl -> fl_Key;
  1890.  
  1891.           if( sh = (struct StreamHandle *)AllocVec( sizeof( struct StreamHandle ), MEMF_PUBLIC ) )
  1892.           {
  1893.             /* init StreamHandle */
  1894.             sh -> sl      = (&(msid -> Demux . fd_demuxa[ stream_index ]));
  1895.             sh -> currpos = 0L;
  1896.  
  1897.             /* Init FileHandle */
  1898.             fh -> fh_Port     = (struct MsgPort *)DOSFALSE;                   /* non-interactive handler    */
  1899.             fh -> fh_Arg1     = (LONG)sh;                                     /* set to struct StreamHandle */
  1900.             fh -> fh_Type     = (&(msid -> Handler . Process -> pr_MsgPort));
  1901.  
  1902.             /* Handler in-use */
  1903.             msid -> Handler . OpenCount++;
  1904.  
  1905.             if( (dp -> dp_Type) == ACTION_FH_FROM_LOCK )
  1906.             {
  1907.               /* Here we can "eat" the given filelock... */
  1908.               FreeLock( cb, msid, fl );
  1909.             }
  1910.  
  1911.             dp -> dp_Res1 = DOSTRUE;  /* success */
  1912.             dp -> dp_Res2 = 0L;       /* No error */
  1913.           }
  1914.           else
  1915.           {
  1916.             dp -> dp_Res1 = DOSFALSE; /* failure */
  1917.             dp -> dp_Res2 = IoErr();  /* Cause ? */
  1918.           }
  1919.       }
  1920.           break;
  1921.  
  1922.       case ACTION_END:
  1923.       {
  1924.           sh = (struct StreamHandle *)(dp -> dp_Arg1);
  1925.  
  1926.           if( sh )
  1927.           {
  1928.             FreeVec( sh );
  1929.           }
  1930.  
  1931.           msid -> Handler . OpenCount--;
  1932.  
  1933.           dp -> dp_Res1 = DOSTRUE;
  1934.           dp -> dp_Res2 = 0L;
  1935.       }
  1936.           break;
  1937.  
  1938.       case ACTION_READ:
  1939.       {
  1940.           LONG                stream_offset  = 0L;
  1941.           LONG                read_size      = (dp -> dp_Arg3);
  1942.           UBYTE              *dest           = (UBYTE *)(dp -> dp_Arg2);
  1943.           LONG                error          = 0L;
  1944.           LONG                curr_read_size = 0L; /* bytes already in buffer */
  1945.           LONG                numpkt         = 0L; /* pending packets */
  1946.           struct FileHandle  *fh;
  1947.           struct PacketBlock *worknode,
  1948.                              *nextnode;
  1949.  
  1950.           sh = (struct StreamHandle *)(dp -> dp_Arg1);
  1951. /* We use "fdin" instead of "sl_handle" here because our whole bunch of virtual streams are mapped to
  1952.  * one real system stream. "sl_handle" would only be used if we have one real stream handle for each
  1953.  * of our virtual handles. The same refers to the actual file position of the real stream handle
  1954.  * (see "classdata.h", "sl_handle_pos".
  1955.  */
  1956. #ifdef COMMENTED_OUT
  1957.           fh = BADDR( (sh -> sl -> sl_handle) );
  1958. #else
  1959.           fh = BADDR( (msid -> Demux . fdin) );
  1960. #endif /* COMMENTED_OUT */
  1961.  
  1962.           worknode = (struct PacketBlock *)(sh -> sl -> sl_packetblocklist . mlh_Head);
  1963.  
  1964.           while( (nextnode = (struct PacketBlock *)(worknode -> node . mln_Succ)) && (read_size > 0UL) )
  1965.           {
  1966.             /* Find start block */
  1967.             if( (stream_offset <= (sh -> currpos)) &&
  1968.                 ((stream_offset + (worknode -> length)) > (sh -> currpos)) )
  1969.             {
  1970.               LONG cut          = ((sh -> currpos) - stream_offset),
  1971.                    curr_readlen = MIN( read_size, ((worknode -> length) - cut) );
  1972.               LONG abs_seek_pos; /* seek position, relative from the beginning of the file */
  1973.  
  1974. #if 0
  1975.               if( Seek( (sh -> sl -> sl_handle), ((worknode -> system_offset) + cut), OFFSET_BEGINNING ) == -1L )
  1976.               {
  1977.                 break;
  1978.               }
  1979. #else
  1980.               abs_seek_pos = ((worknode -> system_offset) + cut);
  1981.  
  1982.               if( SendSeek( cb, msid, fh, (abs_seek_pos - (LONG)(msid -> Demux . fdin_pos)), OFFSET_CURRENT ) )
  1983.               {
  1984.                 numpkt++;
  1985.  
  1986.                 msid -> Demux . fdin_pos = abs_seek_pos;
  1987.               }
  1988.               else
  1989.               {
  1990.                 error = IoErr();
  1991.                 break;
  1992.               }
  1993. #endif
  1994.  
  1995.               /* We only need to check for a "complete fill" or failure, because the previous scan
  1996.                * (in the demuxer part) gurantees that the buffer (packet) has at least this ("curr_readlen") size
  1997.                */
  1998. #if 0
  1999.               if( Read( (sh -> sl -> sl_handle), dest, curr_readlen ) != curr_readlen )
  2000.               {
  2001.                 error = IoErr();
  2002.                 break;
  2003.               }
  2004. #else
  2005.               if( SendRead( cb, msid, fh, dest, curr_readlen ) )
  2006.               {
  2007.                 numpkt++;
  2008.  
  2009.                 msid -> Demux . fdin_pos += curr_readlen;
  2010.               }
  2011.               else
  2012.               {
  2013.                 error = IoErr();
  2014.                 break;
  2015.               }
  2016. #endif
  2017.  
  2018.               dest           += curr_readlen;
  2019.               read_size      -= curr_readlen;
  2020.               curr_read_size += curr_readlen;
  2021.               sh -> currpos  += curr_readlen;
  2022.  
  2023.               /* Should never ever happen, but... */
  2024.               if( read_size < 0L )
  2025.               {
  2026.                 error = ERROR_BUFFER_OVERFLOW;
  2027.                 break;
  2028.               }
  2029.             }
  2030.  
  2031.             stream_offset += worknode -> length;
  2032.  
  2033.             worknode = nextnode;
  2034.           }
  2035.  
  2036. #if 1
  2037.           /* Wait for outstanding msgs and fetch success/errorc codes from them */
  2038.           while( numpkt > 0L )
  2039.           {
  2040.             struct Message *msg;
  2041.  
  2042.             WaitPort( (msid -> Handler . mp) );
  2043.  
  2044.             while( msg = GetMsg( (msid -> Handler . mp) ) )
  2045.             {
  2046.               struct DosPacket *rdp = (struct DosPacket *)(msg -> mn_Node . ln_Name);
  2047.  
  2048.               /* This assumes that we only get ACTION_SEEK/ACTION_READ here back... */
  2049.               if( (rdp -> dp_Res1) == -1L )
  2050.               {
  2051.                 error = rdp -> dp_Res2;
  2052.               }
  2053.  
  2054.               ReleaseDOSPacket( cb, msid, rdp );
  2055.               numpkt--;
  2056.             }
  2057.           }
  2058. #endif
  2059.  
  2060.           /* Resync on error. Required because we don't know whether the ACTION_READ (see above)
  2061.            * was executed or not.
  2062.            */
  2063.           if( error )
  2064.           {
  2065.             msid -> Demux . fdin_pos = Seek( (msid -> Demux . fdin), 0L, OFFSET_CURRENT );
  2066.           }
  2067.  
  2068.           dp -> dp_Res1 = ((error)?(-1L):(curr_read_size)); /* bytes read */
  2069.           dp -> dp_Res2 = error;                            /* result2    */
  2070.       }
  2071.           break;
  2072.  
  2073.       case ACTION_SEEK:
  2074.       {
  2075.           LONG newpos = 0L;
  2076.  
  2077.           sh = (struct StreamHandle *)(dp -> dp_Arg1);
  2078.  
  2079.           switch( dp -> dp_Arg3 )
  2080.           {
  2081.             case OFFSET_BEGINNING:
  2082.             {
  2083.                 newpos = dp -> dp_Arg2;
  2084.             }
  2085.                 break;
  2086.  
  2087.             case OFFSET_CURRENT:
  2088.             {
  2089.                 newpos += (sh -> currpos) + (dp -> dp_Arg2);
  2090.             }
  2091.                 break;
  2092.  
  2093.             case OFFSET_END:
  2094.             {
  2095.                 newpos += (sh -> sl -> sl_size) + (dp -> dp_Arg2);
  2096.             }
  2097.                 break;
  2098.  
  2099.             default: /* should return ERROR_SEEK_ERROR */
  2100.             {
  2101.                 newpos = -1L; /* forces ERROR_SEEK_ERROR by bounds check below */
  2102.             }
  2103.                 break;
  2104.           }
  2105.  
  2106.           /* Check bounds */
  2107.           if( (newpos > (sh -> sl -> sl_size)) || (newpos < 0L) )
  2108.           {
  2109.             dp -> dp_Res1  = -1L;
  2110.             dp -> dp_Res2  = ERROR_SEEK_ERROR;
  2111.           }
  2112.           else
  2113.           {
  2114.             dp -> dp_Res1  = sh -> currpos; /* Return abolsute position BEFORE the seek took place */
  2115.             dp -> dp_Res2  = 0L;
  2116.  
  2117.             sh -> currpos = newpos;
  2118.           }
  2119.       }
  2120.           break;
  2121.  
  2122.       case ACTION_COPY_DIR_FH:
  2123.       {
  2124.           struct FileLock     *dest;
  2125.           struct StreamList   *sl  = ((struct StreamHandle *)(dp -> dp_Arg1)) -> sl;
  2126.  
  2127.           if( dest = (struct FileLock *)AllocVec( sizeof( struct FileLock ), MEMF_PUBLIC ) )
  2128.           {
  2129.             LONG stream_index = (sl - (&(msid -> Demux . fd_demuxa[ 0 ]))); /* Return array index of "sl" */
  2130.  
  2131.             dest -> fl_Link    = NULL;
  2132.             dest -> fl_Key     = stream_index;
  2133.             dest -> fl_Access  = ACCESS_READ;
  2134.             dest -> fl_Task    = (&(msid -> Handler . Process -> pr_MsgPort));
  2135.             dest -> fl_Volume  = NULL;
  2136.  
  2137.             msid -> Handler . OpenCount++;
  2138.           }
  2139.  
  2140.           dp -> dp_Res1 = MKBADDR( dest );
  2141.           dp -> dp_Res2 = (dp -> dp_Res1)?(0L):(IoErr());
  2142.       }
  2143.           break;
  2144.  
  2145.       case ACTION_COPY_DIR:
  2146.       {
  2147.           struct FileLock *src  = (struct FileLock *)BADDR( (dp -> dp_Arg1) ),
  2148.                           *dest;
  2149.  
  2150.           if( dest = (struct FileLock *)AllocVec( sizeof( struct FileLock ), MEMF_PUBLIC ) )
  2151.           {
  2152.             if( (LONG)src > 256L )
  2153.             {
  2154.               *dest = *src;
  2155.  
  2156.               msid -> Handler . OpenCount++;
  2157.             }
  2158.             else
  2159.             {
  2160.               LONG key = ((LONG)src / 16); /* src is now the index... */
  2161.  
  2162.               /* Does we have a system stream to work on ? */
  2163.               if( msid -> Demux . fd_demuxa[ key ] . sl_handle )
  2164.               {
  2165.                 dest -> fl_Link    = NULL;
  2166.                 dest -> fl_Key     = key;
  2167.                 dest -> fl_Access  = ACCESS_READ;
  2168.                 dest -> fl_Task    = (&(msid -> Handler . Process -> pr_MsgPort));
  2169.                 dest -> fl_Volume  = NULL;
  2170.  
  2171.                 msid -> Handler . OpenCount++;
  2172.               }
  2173.               else
  2174.               {
  2175.                 FreeVec( dest );
  2176.                 dest = NULL;
  2177.  
  2178.                 SetIoErr( ERROR_OBJECT_NOT_FOUND );
  2179.               }
  2180.             }
  2181.           }
  2182.  
  2183.           dp -> dp_Res1 = MKBADDR( dest );
  2184.           dp -> dp_Res2 = (dp -> dp_Res1)?(0L):(IoErr());
  2185.       }
  2186.           break;
  2187.  
  2188.       case ACTION_FREE_LOCK:
  2189.       {
  2190.           struct FileLock *fl = (struct FileLock *)BADDR( (dp -> dp_Arg1) );
  2191.  
  2192.           FreeLock( cb, msid, fl );
  2193.  
  2194.           dp -> dp_Res1 = DOSTRUE;
  2195.           dp -> dp_Res2 = 0L;
  2196.       }
  2197.           break;
  2198.  
  2199.       case ACTION_IS_FILESYSTEM:
  2200.       {
  2201.           dp -> dp_Res1 = DOSTRUE;  /* We are a filesystem */
  2202.           dp -> dp_Res2 = 0L;       /* Avoid Lock( ":", SHARED_LOCK ); overhead,
  2203.                                      * see Ralf Babel's "The Amiga GURU Book",
  2204.                                      * section 21.2.3.17, page 621
  2205.                                      */
  2206.       }
  2207.           break;
  2208.  
  2209.       case ACTION_EXAMINE_OBJECT:
  2210.       {
  2211.           struct FileLock      *fl             = (struct FileLock      *)BADDR( (dp -> dp_Arg1) );
  2212.           struct FileInfoBlock *fib            = (struct FileInfoBlock *)BADDR( (dp -> dp_Arg2) );
  2213.           LONG                  stream_index   = fl -> fl_Key;
  2214.           struct StreamList    *sl             = (&(msid -> Demux . fd_demuxa[ stream_index ]));
  2215.  
  2216.           dp -> dp_Res1 = ExamineFH( (sl -> sl_handle), fib );
  2217.  
  2218.           if( dp -> dp_Res1 )
  2219.           {
  2220.             TEXT buffer[ 256 ];
  2221.  
  2222.             mysprintf( cb, buffer, "%s@%ld", (fib -> fib_FileName), stream_index );
  2223.             stccpy( (fib -> fib_FileName), buffer, sizeof( (fib -> fib_FileName) ) );
  2224.  
  2225.             /* Set our stream size */
  2226.             fib -> fib_Size = sl -> sl_size;
  2227.  
  2228.             /* Bump number of blocks */
  2229.             fib -> fib_NumBlocks = INTDIVR( (sl -> sl_size), 1024UL ); /* BUG: Should be packet size to allow faster reading
  2230.                                                                         * in conjunction with async I/O
  2231.                                                                         */
  2232.  
  2233.             /* Convert to BCPL strings */
  2234.             STRPTR2BSTR( (fib -> fib_FileName) );
  2235.             STRPTR2BSTR( (fib -> fib_Comment)  );
  2236.  
  2237.             dp -> dp_Res2 = 0L;
  2238.           }
  2239.           else
  2240.           {
  2241.             dp -> dp_Res2 = IoErr();
  2242.           }
  2243.       }
  2244.           break;
  2245.  
  2246.       case ACTION_PARENT:
  2247.       {
  2248.           struct FileLock      *fl             = (struct FileLock *)BADDR( (dp -> dp_Arg1) );
  2249.           LONG                  stream_index   = fl -> fl_Key;
  2250.           struct StreamList    *sl             = (&(msid -> Demux . fd_demuxa[ stream_index ]));
  2251.  
  2252.           dp -> dp_Res1 = ParentOfFH( (sl -> sl_handle) ); /* Get parent of system stream */
  2253.           dp -> dp_Res2 = IoErr();
  2254.       }
  2255.           break;
  2256.  
  2257.       case ACTION_INFO: /* Required for async I/O */
  2258.       default:
  2259.       {
  2260.           dp -> dp_Res1 = DOSFALSE;
  2261.           dp -> dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  2262.       }
  2263.           break;
  2264.     }
  2265.  
  2266.     rport = dp -> dp_Port;
  2267.     dp -> dp_Port = (&(msid -> Handler . Process -> pr_MsgPort));
  2268.  
  2269.     PutMsg( rport, (dp -> dp_Link) );
  2270. }
  2271.  
  2272.  
  2273. /* Convert a C string into a BCPL string */
  2274. static
  2275. void STRPTR2BSTR( STRPTR s )
  2276. {
  2277.     size_t len = strlen( s );
  2278.  
  2279.     memmove( (&s[ 1 ]), s, len );
  2280.     s[ 0 ] = len; /* WARNING: Assumes that the string is less than < 255 bytes ! */
  2281. }
  2282.  
  2283.  
  2284. static
  2285. void FreeLock( struct ClassBase *cb, struct MPEGSystemInstData *msid, struct FileLock *fl )
  2286. {
  2287.     if( fl )
  2288.     {
  2289.       fl -> fl_Task = NULL; /* Any attempt to use the FileLock again should be DEADLY !! */
  2290.  
  2291.       msid -> Handler . OpenCount--;
  2292.  
  2293.       FreeVec( fl );
  2294.     }
  2295. }
  2296.  
  2297.  
  2298. /* Fetch a DosPacket from our private pool */
  2299. static
  2300. struct DosPacket *ObtainDOSPacket( struct ClassBase *cb, struct MPEGSystemInstData *msid )
  2301. {
  2302.     struct DosPacket *dp;
  2303.     struct Node      *node;
  2304.  
  2305.     if( node = RemHead( (struct List *)(&(msid -> Handler . pktpool)) ) )
  2306.     {
  2307.       dp = (struct DosPacket *)(node -> ln_Name);
  2308.     }
  2309.     else
  2310.     {
  2311.       dp = (struct DosPacket *)AllocDosObject( DOS_STDPKT, NULL );
  2312.     }
  2313.  
  2314.     return( dp );
  2315. }
  2316.  
  2317.  
  2318. /* Return a DosPacket to our private pool */
  2319. static
  2320. void ReleaseDOSPacket( struct ClassBase *cb, struct MPEGSystemInstData *msid, struct DosPacket *dp )
  2321. {
  2322.     AddTail( (struct List *)(&(msid -> Handler . pktpool)), (&(dp -> dp_Link -> mn_Node)) );
  2323. }
  2324.  
  2325.  
  2326. /* Send a seek async */
  2327. static
  2328. BOOL SendSeek( struct ClassBase *cb, struct MPEGSystemInstData *msid, struct FileHandle *fh, LONG pos, LONG mode )
  2329. {
  2330.     struct DosPacket *dp;
  2331.  
  2332.     if( dp = ObtainDOSPacket( cb, msid ) )
  2333.     {
  2334.       dp -> dp_Type = ACTION_SEEK;
  2335.       dp -> dp_Arg1 = fh -> fh_Arg1;
  2336.       dp -> dp_Arg2 = pos;
  2337.       dp -> dp_Arg3 = mode;
  2338.  
  2339.       dp -> dp_Port = dp -> dp_Link -> mn_ReplyPort = msid -> Handler . mp;
  2340.       PutMsg( (fh -> fh_Type), (dp -> dp_Link) );
  2341.  
  2342.       return( TRUE );
  2343.     }
  2344.  
  2345.     return( FALSE );
  2346. }
  2347.  
  2348.  
  2349. /* Send a read async */
  2350. static
  2351. BOOL SendRead( struct ClassBase *cb, struct MPEGSystemInstData *msid, struct FileHandle *fh, UBYTE *buffer, ULONG len )
  2352. {
  2353.     struct DosPacket *dp;
  2354.  
  2355.     if( dp = ObtainDOSPacket( cb, msid ) )
  2356.     {
  2357.       dp -> dp_Type = ACTION_READ;
  2358.       dp -> dp_Arg1 = fh -> fh_Arg1;
  2359.       dp -> dp_Arg2 = (LONG)buffer;
  2360.       dp -> dp_Arg3 = len;
  2361.  
  2362.       dp -> dp_Port = dp -> dp_Link -> mn_ReplyPort = msid -> Handler . mp;
  2363.       PutMsg( (fh -> fh_Type), (dp -> dp_Link) );
  2364.  
  2365.       return( TRUE );
  2366.     }
  2367.  
  2368.     return( FALSE );
  2369. }
  2370.  
  2371.  
  2372.  
  2373.  
  2374.  
  2375.